#include "test_report_win32.h"
#include "widgets.h"
#include "observer.h"
#include <commctrl.h>
#include <windowsx.h>

using namespace krryn::gui;
using namespace krryn::core;
using namespace krryn::test;

// Generate manifest for comctl 6.0 instead of the default 5.0
// (mainly for looks ;-))
#pragma comment(linker, \
    "\"/manifestdependency:type='Win32' "\
    "name='Microsoft.Windows.Common-Controls' "\
    "version='6.0.0.0' "\
    "processorArchitecture='*' "\
    "publicKeyToken='6595b64144ccf1df' "\
    "language='*'\"")

namespace krryn{
namespace test{
	size_t test_report_win32::m_MaxTotal = 0;
	size_t test_report_win32::m_Progress = 0;


	NONCLIENTMETRICS *helper_win32::m_NonClientMetrics = 0;
	int helper_win32::m_CurrentWidgetId = 100;
	std::map<int, widget_win32*> helper_win32::m_widgets = std::map<int, widget_win32*>();


	class tree_view_node_win32{
	public:
		tree_view_node *m_Node;
		std::string m_Parent;
		HTREEITEM hItem;

		tree_view_node_win32(tree_view_node *a_Node, std::string a_Parent)
			: m_Node(a_Node), m_Parent(a_Parent) {}
	};
}
namespace gui{
	window *create_window(){
		return new window_win32();
	}
}
}

button *window_win32::create_button(){
	return new button_win32(this);
}

progress_bar *window_win32::create_progress_bar(){
	return new progress_bar_win32(this);
}

tree_view *window_win32::create_tree_view(){
	return new tree_view_win32(this);
}

void helper_win32::dispatch(WPARAM wParam, LPARAM lParam){
	int l_Id = LOWORD(wParam);

	if(m_widgets[l_Id] != 0){
		m_widgets[l_Id]->notify(wParam, lParam);
	}
}

HMENU helper_win32::register_object(widget_win32 *a_widget){
	int l_Id = m_CurrentWidgetId++;
	m_widgets[l_Id] = a_widget;
	return (HMENU)l_Id;
}

void helper_win32::update_font(HWND hWnd){
	SendMessage(
		hWnd, 
		WM_SETFONT, 
		(WPARAM)CreateFontIndirect(&(get_non_client_metrics()->lfMessageFont)), 
		TRUE
	);
}

NONCLIENTMETRICS* helper_win32::get_non_client_metrics(){
	if(!m_NonClientMetrics){
		m_NonClientMetrics = new NONCLIENTMETRICS();
		m_NonClientMetrics->cbSize = sizeof(NONCLIENTMETRICS);

		SystemParametersInfo(
			SPI_GETNONCLIENTMETRICS, m_NonClientMetrics->cbSize, 
			m_NonClientMetrics, 0);
	}

	return m_NonClientMetrics;
}

button_win32::button_win32(widget *a_Parent) : button(a_Parent) {
	hWnd = CreateWindow(
		"BUTTON",
		"",
		WS_CHILD | WS_VISIBLE,
		210, 20, 100, 20,
		dynamic_cast<widget_win32*>(m_Parent)->hWnd, helper_win32::register_object(this), (HINSTANCE)GetModuleHandle(NULL), NULL);

	helper_win32::update_font(hWnd);
}

void button_win32::do_layout(){

}



void button_win32::notify(WPARAM wParam, LPARAM lParam){
	switch(HIWORD(wParam)){
		case BN_CLICKED:
			basic_args l_Args;
			m_OnClick.trigger(&l_Args);
			break;
	}
}

progress_bar_win32::progress_bar_win32(widget *a_Parent) : progress_bar(a_Parent){
	hWnd = CreateWindow(
		PROGRESS_CLASS,
		"krryn::progress_bar",
		WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
		10, 10, 100, 17,
		dynamic_cast<widget_win32*>(m_Parent)->hWnd, helper_win32::register_object(this), (HINSTANCE)GetModuleHandle(NULL), NULL);
}

void progress_bar_win32::do_layout(){
	SendMessage(hWnd, PBM_SETBARCOLOR, RGB(255, 0, 0), 0);
}

window_win32::window_win32() : window(), m_Title(""){
	//FreeConsole(); // Close console window

	WNDCLASSEX wc;

	InitCommonControls();

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = window_win32::wnd_proc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = (HINSTANCE)GetModuleHandle(NULL);
	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = TEXT("krryn");
	wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

	RegisterClassEx(&wc);

	hWnd = CreateWindow(
		wc.lpszClassName,
		m_Title.c_str(),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
		NULL, NULL, wc.hInstance, NULL);
}

void window_win32::show(){
	ShowWindow(hWnd, SW_SHOWNORMAL);
	UpdateWindow(hWnd);
}

void window_win32::do_layout(){
	MSG Msg;

	if(GetMessage(&Msg, NULL, 0, 0) > 0){
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
}

void helper_win32::set_size(HWND hWnd, int a_Width, int a_Height){
	SetWindowPos(hWnd, 0, 0, 0, a_Width, a_Height, SWP_NOMOVE);
}

void helper_win32::set_position(HWND hWnd, int a_X, int a_Y){
	SetWindowPos(hWnd, 0, a_X, a_Y, 0, 0, SWP_NOSIZE);
}

void window_win32::set_size(int a_Width, int a_Height){
	helper_win32::set_size(hWnd, a_Width, a_Height);
}

void window_win32::set_position(int a_X, int a_Y){
	helper_win32::set_position(hWnd, a_X, a_Y);
}

void window_win32::set_caption(const std::string &a_Text){
	SetWindowText(hWnd, a_Text.c_str());
}

void progress_bar_win32::set_size(int a_Width, int a_Height){
	helper_win32::set_size(hWnd, a_Width, a_Height);
}

void progress_bar_win32::set_position(int a_X, int a_Y){
	helper_win32::set_position(hWnd, a_X, a_Y);
}

void progress_bar_win32::set_range(int a_Begin, int a_End){
	// set the range
	SendMessage(hWnd, PBM_SETRANGE, 0, MAKELPARAM(a_Begin, a_End)); 
}

void progress_bar_win32::set_progress(int a_Progress){
	// and position
	SendMessage(hWnd, PBM_SETPOS, a_Progress, 0);
}

void button_win32::set_caption(const std::string &a_Text){
	Button_SetText(hWnd, a_Text.c_str());
}

void button_win32::set_size(int a_Width, int a_Height){
	helper_win32::set_size(hWnd, a_Width, a_Height);
}

void button_win32::set_position(int a_X, int a_Y){
	helper_win32::set_position(hWnd, a_X, a_Y);
}

tree_view_win32::tree_view_win32(widget *a_Parent) : tree_view(a_Parent){
	hWnd = CreateWindowEx(
		WS_EX_CLIENTEDGE,
		WC_TREEVIEW,
		"krryn::tree_view",
		WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_LINESATROOT,
		0, 0, 100, 100,
		dynamic_cast<widget_win32*>(m_Parent)->hWnd,
		helper_win32::register_object(this), 
		(HINSTANCE)GetModuleHandle(NULL), NULL);
}

void tree_view_win32::do_layout(){	
}

void tree_view_win32::set_size(int a_Width, int a_Height){
	helper_win32::set_size(hWnd, a_Width, a_Height);
}

void tree_view_win32::set_position(int a_X, int a_Y){
	helper_win32::set_position(hWnd, a_X, a_Y);
}

void tree_view_win32::add_node(tree_view_node *a_Node, const std::string &a_ParentKey){
	if(m_Nodes[a_Node->m_Key]){
		throw gui::gui_exception("Key '" + a_Node->m_Key + "' is already in use");
	}

	m_Nodes[a_Node->m_Key] = new tree_view_node_win32(a_Node, a_ParentKey);

	TV_INSERTSTRUCT l_Insert;

	l_Insert.item.mask		 = TVIF_TEXT;
	l_Insert.item.pszText	 = strdup(a_Node->m_Title.c_str());
	l_Insert.item.cchTextMax = a_Node->m_Title.length();

	l_Insert.hParent = NULL;
	l_Insert.hInsertAfter = (HTREEITEM)TVI_ROOT;

	if(!a_ParentKey.empty()){
		if(m_Nodes[a_ParentKey]){
			l_Insert.hParent = m_Nodes[a_ParentKey]->hItem;
			l_Insert.hInsertAfter = (HTREEITEM)TVI_LAST;
		}else{
			throw gui::gui_exception("Parent '" + a_ParentKey + "' does not exist");
		}
	}

	m_Nodes[a_Node->m_Key]->hItem = (HTREEITEM)SendMessage(hWnd, TVM_INSERTITEM,
		0, (LPARAM)&l_Insert);

	// Expand parent so this item is visible
	if(l_Insert.hParent != NULL){
		SendMessage(hWnd, TVM_EXPAND, TVE_EXPAND, (LPARAM)l_Insert.hParent);
	}
}

LRESULT CALLBACK window_win32::wnd_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam){
	switch(Msg){
	case WM_CREATE:
		break;
	case WM_CLOSE:
		DestroyWindow(hWnd);
		exit(0);
		break;
	case WM_KEYDOWN:
		if(wParam == VK_ESCAPE) exit(0);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_COMMAND:
		if(wParam > 1){
			helper_win32::dispatch(wParam, lParam);
		}

		break;
	default:
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}
	return 0;
}